#ifndef _MCMC_MOVE_BOUNDARY_H
#define _MCMC_MOVE_BOUNDARY_H

#include "mcmcLayerRegionElements.h"

#define MC_MB_LEFT		2
#define MC_MB_RIGHT		0
#define MC_MB_UP		3
#define MC_MB_DOWN		1

#define	MB_CSEG_LEFT	0
#define	MB_CSEG_RIGHT	1


// used for keeping track of the topology change for the nodes on the moving boundary
class MbRelativePosition
{
public:
	void Set(const McImagePoint &grid, const McImagePoint &grid_right, const McImagePoint &grid_top)
	{
		j_right = grid_right.Row()-grid.Row();
		i_right = grid_right.Col()-grid.Col();

		j_left = -j_right;
		i_left = -i_right;

		j_top = grid_top.Row()-grid.Row();
		i_top = grid_top.Col()-grid.Col();

		j_bottom = -j_top;
		i_bottom = -i_top;
	}

	inline void	GetGridLeft(McImagePoint &grid, const int j, const int i)
	{
		grid.SetRow(j+j_left);
		grid.SetCol(i+i_left);
	}
	inline void	GetGridRight(McImagePoint &grid, const int j, const int i)
	{
		grid.SetRow(j+j_right);
		grid.SetCol(i+i_right);
	}
	inline void	GetGridTop(McImagePoint &grid, const int j, const int i)
	{
		grid.SetRow(j+j_top);
		grid.SetCol(i+i_top);
	}
	inline void	GetGridBottom(McImagePoint &grid, const int j, const int i)
	{
		grid.SetRow(j+j_bottom);
		grid.SetCol(i+i_bottom);
	}
	inline void GetGridPos(McImagePoint &grid, const McImagePoint grid1, const int k)
	{
		switch (k)
		{
		case MC_MB_RIGHT:	GetGridRight(grid, grid1.Row(), grid1.Col());	return;
		case MC_MB_DOWN:	GetGridBottom(grid, grid1.Row(), grid1.Col());	return;
		case MC_MB_LEFT:	GetGridLeft(grid, grid1.Row(), grid1.Col());	return;
		case MC_MB_UP:		GetGridTop(grid, grid1.Row(), grid1.Col());		return;
		}

	}

protected:
	int	i_left,j_left;
	int	i_top,j_top;
	int	i_right,j_right;
	int	i_bottom,j_bottom;
};

class MbNodeTopologyRecord
{
public:
	// construction & destruction
	MbNodeTopologyRecord();

	// operations
	void	Init(const McImagePoint &grid1, MbRelativePosition &rp, MCMC_Layer_Regions *pgraph1);
	int	NumConnections(void);
	int	NumAllConnections(void);
	inline MCMC_Contour_Segment* GetCSegWithNeighbor(const int i);
	inline int					 GetNodeNeightbor(const int i);

	MCMC_Node		*pnode;
	int				id_node;
	McImagePoint	grid;
	McImagePoint	grid_neighbors[4];
	MCMC_Vertex		*pver;

	uchar			connections_after[4];
	bool			deleted;

protected:
	MCMC_Layer_Regions *player_region;
};

class MCMC_MoveBoundary
{
public:
	// construction & destruction
	MCMC_MoveBoundary(MCMC_Layer_Regions *pgraph1);
	~MCMC_MoveBoundary(){player_region=NULL;};

	// access
	inline MCMC_Layer_Regions*	LayerRegion(void){return player_region;};

	// operations related to moving the boundaries
	int		MoveNodes(MCMC_Contour_Segment *pcseg, const int id_node1, const int id_node2, const uchar left_or_right, const bool swaped=false);
	void	RandomMove(void);
	bool	CheckConsistencyOfTopologyRecord(void);

protected:
	// operations related to moving boundaries
	int		CreateVertexAndBreakCSegs(MbNodeTopologyRecord &node, MbNodeTopologyRecord &node_top, MbNodeTopologyRecord &node_right);
	int		BreakContourSegment(MCMC_Contour_Segment *pcseg, MCMC_Vertex *pver1, const int id_node1, const int id_node_ref);
	void	ConnectContourSegments(void);

	// operations related to moving boundaries
	bool	IsMoveAllowed(const int j_change, const int i_change, const uchar horizontal_or_vertical, const char go_plus_or_minus);

	void	MakeTheMove(MCMC_Contour_Segment* pcseg, const int j_from, const int i_from);
	void	MoveMakeTwoNodesCase1(MCMC_Contour_Segment* pcseg);
	void	MoveMakeTwoNodesCase2(MCMC_Contour_Segment* pcseg, MbNodeTopologyRecord &node_a1, MbNodeTopologyRecord &node_a2, MbNodeTopologyRecord &node_a1_to, MbNodeTopologyRecord &node_a2_to);
	void	MoveMakeTwoNodesCase3(MCMC_Contour_Segment* pcseg, const int j_from, const int i_from);
	bool	IsSpecialCase3(MCMC_Contour_Segment* pcseg);
	bool	DeleteTwoNodes(MCMC_Contour_Segment* pcseg, MbNodeTopologyRecord &node_keep1, MbNodeTopologyRecord &node_keep2, MbNodeTopologyRecord &node_del1, MbNodeTopologyRecord &node_del2);
	void	DeleteTheNodesIfNecessary(MCMC_Contour_Segment* pcseg, MbNodeTopologyRecord &node1, MbNodeTopologyRecord &node2,
										MbNodeTopologyRecord &node1_to, MbNodeTopologyRecord &node2_to, const int id_node_extn);
	void	MergeSegments(MCMC_Contour_Segment *pcseg1, MCMC_Contour_Segment *pcseg2, MbNodeTopologyRecord &node_a, MbNodeTopologyRecord &node_b); // merge the two contour segments into one by id_cseg1
	void	UpdateCSegIdOnGrid(MCMC_Contour_Segment *pcseg, const int id_replace);
	void	ExtendContour(MCMC_Contour_Segment *pcseg, MbNodeTopologyRecord *ptr_nodes[4], const int i, const int j);

public:
	int	p_nodes_next_to_move[4];

protected:
	MCMC_Layer_Regions	*player_region;
	MbNodeTopologyRecord node1;
	MbNodeTopologyRecord node2;
	MbNodeTopologyRecord node1_to;
	MbNodeTopologyRecord node2_to;

	int				labels[6];
	int				left_right[3][2];
	int				signs_connections[4];
};


#endif
